package com.example.util;

import org.apache.tomcat.util.codec.binary.Base64;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**RSA 加密解密工具类
 *
 * @email: pengyujun53@163.com
 * @author: peng_YuJun
 * @date: 2022/11/17
 * @time: 20:13
 */
public class RsaUtil {
    //加密方法
    private static final String ALGORITHE = "RSA";

    private static final String UTF8 = StandardCharsets.UTF_8.name();

    //rsa单次加密最大明文大小
    private static final int MAX_ENCRYPT_BLOCK = 117;

    //rsa单次解密最大明文大小
    private static final int MAX_DECRYPT_BLOCK = 128;

    // 前端用 PUBLIC_KEY加密 PRIVATE_KEY2解密
    // 后端用 PRIVATE_KEY解密 PUBLIC_KEY2加密
    private static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCodhipA7Ptytbo2GuJ7DK9FU31H3X2NYKCcvkMVydMTVVdu5TaWaZ6RPYUEieevcfqm8zcAiyZ+Xu35Gm8OvY9+Y5mtWp26XxdF9yTNBGIHx721oOC0K/bRiy9ypVhLyj7NlNRSEdDjmRIBoxdyDXg58XaSysSqRQt/0k0M65K2QIDAQAB";
    private static final String PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKh2GKkDs+3K1ujYa4nsMr0VTfUfdfY1goJy+QxXJ0xNVV27lNpZpnpE9hQSJ569x+qbzNwCLJn5e7fkabw69j35jma1anbpfF0X3JM0EYgfHvbWg4LQr9tGLL3KlWEvKPs2U1FIR0OOZEgGjF3INeDnxdpLKxKpFC3/STQzrkrZAgMBAAECgYAvbtkwtbcy7Fsows88zYHX1ajWrR4UzipKOr8/J0cMZ/XyZ3/ZH0cNxF8ZdacsPjmNKIM9K2uNiz63n5vaASwV/p0Fd4KDuPRz46v/kxaQM6AVBXlty45oyISbcafGs4MwO3hrjVA3eLrcDLrSr+DitEIabe+iWyioy1sUkGjsAQJBAPVNrZQPZGgsnU3QKHj8uKJBtsHaTIPsAGDw2Nnu75wqFLIbxosmBVCHAJMB0gcoaceIdp/myUNFSnF1f4PIJoECQQCvzqE7xTZG/JULZ/nRClwsDLN/PdvDqx1ZOK0f/vZ8+wwad58UlsdkRjtmvPR1WmW6IvcnOMu13pgHW18uNOhZAkEAt1LQEEDYlwoQnWCdfp3QFmLqBEHywPyU493bEjQBGkJQqTMc1E0b16ys/zBzGCpZs2cG0EWX0BBurBBVtdTVAQJAMtZWa1k4u8g4NSco5xjO1HILyaSSkv89KlqoPVNV5YgW1OR4XNTI7acdcDT9n523Qt7vhyj2Ry4J2j7CxDLKaQJARp7jnH1+7n9mVklsnyqeU9Qd9tHHslUzfynrro3LndaG1Q908074SvGBaCHZu3f6dk2EuESCHxY7FqT/AJmErA==";

    private static final String PUBLIC_KEY2 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCukC1YdWYQ6JCkAcOq+4I5fnRo2/jqtH+U3TFjHtblfSV9ZkHCgVxLtuxFsl2jG9Ve4d9dBGbBDpPtPZLrI6tncTSQBkoWvSS63thyy5O0nTONoTKc2AvKG4ljRW+OG8bNv3ibxs5l9iGYbmr62n9AokaUVC3Y6TfrtamhMR2AvQIDAQAB";
    private static final String PRIVATE_KEY2 = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAK6QLVh1ZhDokKQBw6r7gjl+dGjb+Oq0f5TdMWMe1uV9JX1mQcKBXEu27EWyXaMb1V7h310EZsEOk+09kusjq2dxNJAGSha9JLre2HLLk7SdM42hMpzYC8obiWNFb44bxs2/eJvGzmX2IZhuavraf0CiRpRULdjpN+u1qaExHYC9AgMBAAECgYAQAWY2+yStnjVM5GCFd+Qb021nA+xR0NT12EYj+Xrotc3PLqYO6H+G7bHCPjV5tB6fQYSSacnmH6kOkpu69Z1Miv2KX2aUhja8I99YuCNBDo8JppW6tmQb2Sfo2WAVcsJfQvBUEKO1Kr4gPQf7KeVS7n6NXeMl+0TVnyhADn80PQJBANfLg64muvezH+VWKqVrSw8sNBB9qR5v+8C/DucNEtC/ekCmYnh8dgspq9YxeRUMI7EP+04lzPJQHPLB9so3E+cCQQDPFhXN+rf48IEA8ZPgSlvCbROK2qSQYHNCOAgOFNME07DTJkdoqIOlIUrTQ0Ew1Jh0lF9SGRfrBvR3E9Xo/3G7AkBl6pA+Z7xV0Bt4TMHHbmz8tXvBbhe5cFoOJi37oYkJXeV3Mx2+mcmGbB/kAWmWLy2MKmgd+Gxa5MtHO6Q6zNhxAkBtn85ZJOEg+ggAfOIAOLzMdruCpO26tCQvqMOy2JlAk+OmUzw4DgTqdG5M2ex3sgMmq6iuKDR+KUdehfSWDCujAkBKbD9Umg6DDCzWQsrAtm9wEt9uj1F9lTNlira3cye0KnQkbSHaQP0Bw9mPQdiDQxhZ62UNGNGB471Lyz36wytd";

    /**
     * 获取公钥
     * @return
     */
    public static PublicKey getPublicKey() throws Exception {
        //System.out.println("公钥："+publicKey);
        byte[] keyBytes = Base64.decodeBase64(PUBLIC_KEY2);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHE);
        PublicKey publicK =  keyFactory.generatePublic(x509KeySpec);
        return publicK;
    }

    /**
     * 获取私钥
     * @return
     */
    public static PrivateKey getPrivateKey() throws Exception{
        //System.out.println("私钥："+privateKey);
        byte[] keyBytes = Base64.decodeBase64(PRIVATE_KEY);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHE);
        PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        return privateK;
    }
    /**
     * 加密
     * @param originalCont 原始内容
     * @param key 公钥/私钥
     * @return base64编码后的内容
     */
    public static String encrpt(String originalCont, Key key) throws Exception {
        //定义cipher对象
        Cipher cipher = Cipher.getInstance(ALGORITHE);
        cipher.init(Cipher.ENCRYPT_MODE,key);
        originalCont = URLEncoder.encode(originalCont,UTF8).replaceAll("\\+", "%20");
        //开始加密
        byte[] bytes = doCodec(cipher,originalCont.getBytes(UTF8),MAX_ENCRYPT_BLOCK);
        //Base64编码加密后的字符串并返回
        return Base64.encodeBase64String(bytes);
    }

    /**
     * 解密
     *
     * @param encryptedStr 加密后的内容
     * @param key 公钥/私钥
     * @return 原始内容
     * @throws Exception
     */
    public static String decrpt(String encryptedStr,Key key) throws Exception{
        //Base64解码
        byte[] decodeBase64 = Base64.decodeBase64(encryptedStr);
        //定义cipher对象
        Cipher cipher = Cipher.getInstance(ALGORITHE);
        cipher.init(Cipher.DECRYPT_MODE,key);
        //开始解密
        byte[] decrptedBytes = doCodec(cipher,decodeBase64,MAX_DECRYPT_BLOCK);
        //返回解密后的字符串
        return URLDecoder.decode(new String(decrptedBytes),UTF8);
    }

    /**
     * 具体加密或解密
     * @param cipher
     * @param bytes
     * @param maxBlockSize
     * @return
     */
    public static byte[] doCodec(Cipher cipher, byte[] bytes, int maxBlockSize) throws Exception{
        int inputLen = bytes.length;
        int offset = 0;
        byte[] cache;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int i = 0;
        //循环分段处理
        while ((inputLen - offset) > 0){
            if ((inputLen - offset) > maxBlockSize){
                cache = cipher.doFinal(bytes, offset,  maxBlockSize);
            }else {
                cache = cipher.doFinal(bytes, offset, inputLen - offset);
            }
            //把cache的内容存起来
            baos.write(cache,0,cache.length);
            i++;
            offset = i*maxBlockSize;
        }
        //加密或解密的结果
        byte[] codec = baos.toByteArray();
        baos.close();
        return codec;
    }

    /**
     * 生成公钥私钥，并Base64编码
     */
    public static void makeRsaKey() throws Exception{
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHE);
        keyPairGenerator.initialize(1024);
        //通过keyPair生成器生成KeyPair
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        //得到公钥私钥
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();
        //将对象转成字节数组
        byte[] publicKeyEncoded = publicKey.getEncoded();
        byte[] privateKeyEncoded = privateKey.getEncoded();
        //使用base64编码
        String publicKeyBase64 = Base64.encodeBase64String(publicKeyEncoded);
        String privateKeyBase64 = Base64.encodeBase64String(privateKeyEncoded);
        //输出
        System.out.println("公钥：" + publicKeyBase64);
        System.out.println("私钥：" + privateKeyBase64);
    }
}
